home *** CD-ROM | disk | FTP | other *** search
/ Aminet 23 / Aminet 23 (1998)(GTI - Schatztruhe)[!][Feb 1998].iso / Aminet / dev / c / fortify22.lha / FORTIFY.CXX next >
C/C++ Source or Header  |  1995-11-01  |  64KB  |  2,297 lines

  1. /* fortify.cxx - A fortified memory allocation shell - V2.2 */
  2.  
  3. /*
  4.  *     This  software  is  not public domain.  All material in
  5.  * this  archive  is (C) Copyright 1995 Simon P.  Bullen.  The
  6.  * software  is  freely distributable, with the condition that
  7.  * no   more   than  a  nominal  fee  is  charged  for  media.
  8.  * Everything  in  this distribution must be kept together, in
  9.  * original, unmodified form.
  10.  *     The software may be modified for your own personal use,
  11.  * but modified files may not be distributed.
  12.  *     The  material  is  provided "as is" without warranty of
  13.  * any  kind.  The author accepts no responsibility for damage
  14.  * caused by this software.
  15.  *     This  software  may not be used in any way by Microsoft
  16.  * Corporation  or  its  subsidiaries, or current employees of
  17.  * Microsoft Corporation or its subsidiaries.
  18.  *     This  software  may  not  be used for the construction,
  19.  * development,  production,  or  testing of weapon systems of
  20.  * any kind.
  21.  *     This  software  may  not  be used for the construction,
  22.  * development,  production,  or  use  of plants/installations
  23.  * which  include  the  processing  of radioactive/fissionable
  24.  * material.
  25.  */
  26.  
  27. /*  
  28.  *     If  you use this software at all, I'd love to hear from
  29.  * you.   All  questions,  criticisms, suggestions, praise and
  30.  * postcards are most welcome.
  31.  * 
  32.  *            email:    sbullen@cybergraphic.com.au
  33.  * 
  34.  *            snail:    Simon P. Bullen
  35.  *                      PO BOX 12138
  36.  *                      A'Beckett St.
  37.  *                      Melbourne 3000
  38.  *                      Australia
  39.  */
  40.  
  41. #ifdef FORTIFY
  42.  
  43. #include <stdio.h>
  44. #include <stdlib.h>
  45. #include <string.h>
  46. #include <assert.h>
  47. #include <math.h>
  48. #include <ctype.h>
  49. #include <time.h>
  50.  
  51.  
  52. /* the user's options */
  53. #include "ufortify.h"
  54.  
  55. /* Prototypes and such */
  56. #define __FORTIFY_C__
  57. #include "fortify.h"
  58.  
  59.  
  60. /*
  61.  * Round x up to the nearest multiple of n.
  62.  */
  63. #define ROUND_UP(x, n) ((((x) + (n)-1)/(n))*(n))
  64.  
  65. /*
  66.  * struct Header - this structure is used 
  67.  * internally by Fortify to manage it's 
  68.  * own private lists of memory.
  69.  */
  70. struct Header
  71. {
  72.     unsigned short Checksum;    /* For the integrity of our goodies  */
  73.     const char    *File;        /* The sourcefile of the allocator   */
  74.     unsigned long  Line;        /* The sourceline of the allocator   */
  75. #ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
  76.     const char    *FreedFile;   /* The sourcefile of the deallocator */
  77.     unsigned long  FreedLine;   /* The sourceline of the deallocator */
  78.     unsigned char  Deallocator; /* The deallocator used              */
  79. #endif
  80.     size_t         Size;        /* The size of the malloc'd block    */
  81.     struct Header *Prev;        /* Previous link                     */
  82.     struct Header *Next;        /* Next link                         */
  83.     char          *Label;        /* User's Label (may be null)        */
  84.     unsigned char  Scope;       /* Scope level of the caller         */
  85.     unsigned char  Allocator;   /* malloc/realloc/new/etc            */
  86. };
  87.  
  88. #define FORTIFY_HEADER_SIZE ROUND_UP(sizeof(struct Header), sizeof(unsigned short))
  89.  
  90.  
  91.  
  92. /*
  93.  * FORTIFY_ALIGNED_BEFORE_SIZE is FORTIFY_BEFORE_SIZE rounded up to the
  94.  * next multiple of FORTIFY_ALIGNMENT. This is so that we can guarantee
  95.  * the alignment of user memory for such systems where this is important
  96.  * (eg storing doubles on a SPARC)
  97.  */
  98. #define FORTIFY_ALIGNED_BEFORE_SIZE ( \
  99.                    ROUND_UP(FORTIFY_HEADER_SIZE + FORTIFY_BEFORE_SIZE, FORTIFY_ALIGNMENT) \
  100.                    - FORTIFY_HEADER_SIZE)
  101.  
  102. /*
  103.  * FORTIFY_OVERHEAD is the total overhead added by Fortify to each
  104.  * memory block.
  105.  */
  106. #define FORTIFY_OVERHEAD ( FORTIFY_HEADER_SIZE \
  107.                          + FORTIFY_ALIGNED_BEFORE_SIZE \
  108.                          + FORTIFY_AFTER_SIZE) 
  109.  
  110.  
  111. /*
  112.  *
  113.  * Static Function Prototypes
  114.  *
  115.  */
  116. static int  st_CheckBlock(struct Header *h, const char *file, unsigned long line);
  117. static int  st_CheckFortification (unsigned char *ptr, unsigned char value, size_t size);
  118. static void st_SetFortification   (unsigned char *ptr, unsigned char value, size_t size);
  119. static void st_OutputFortification(unsigned char *ptr, unsigned char value, size_t size);
  120. static void st_HexDump(unsigned char *ptr, size_t offset, size_t size, int title);
  121. static int  st_IsHeaderValid(struct Header *h);
  122. static void st_MakeHeaderValid(struct Header *h);
  123. static unsigned short st_ChecksumHeader(struct Header *h);
  124. static int  st_IsOnAllocatedList(struct Header *h);
  125. static void st_OutputHeader(struct Header *h);
  126. static void st_OutputMemory(struct Header *h);
  127. static void st_OutputLastVerifiedPoint(void);
  128. static void st_DefaultOutput(const char *String);
  129. static const char *st_MemoryBlockString(struct Header *h);
  130. static void st_OutputDeleteTrace();
  131.  
  132. #ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
  133. #ifdef FORTIFY_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY
  134. #ifdef FORTIFY_VERBOSE_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY
  135.     static const char *st_DeallocatedMemoryBlockString(struct Header *h);
  136. #endif /* FORTIFY_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY */
  137. #endif /* FORTIFY_VERBOSE_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY */
  138.     static int  st_IsOnDeallocatedList(struct Header *h);
  139.     static int st_PurgeDeallocatedBlocks(unsigned long Bytes, const char *file, unsigned long line);
  140.     static int st_PurgeDeallocatedScope(unsigned char Scope, const char *file, unsigned long line);
  141.     static int st_CheckDeallocatedBlock(struct Header *h, const char *file, unsigned long line);
  142.     static void st_FreeDeallocatedBlock(struct Header *h, const char *file, unsigned long line);
  143. #endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
  144.  
  145.  
  146. /*
  147.  *
  148.  * Static variables
  149.  *
  150.  */
  151. static struct Header *st_AllocatedHead   = 0;
  152. static int  st_AllocateFailRate = 0;
  153. static char st_Buffer[256];
  154. static Fortify_OutputFuncPtr st_Output    = st_DefaultOutput;
  155. static const char    *st_LastVerifiedFile = "unknown";
  156. static unsigned long  st_LastVerifiedLine = 0;
  157. static unsigned char  st_Scope            = 0;
  158. static unsigned char  st_Disabled = 0;
  159.  
  160. #ifdef __cplusplus
  161.     int                   gbl_FortifyMagic = 0;
  162.     static const    char *st_DeleteFile[FORTIFY_DELETE_STACK_SIZE];
  163.     static unsigned long  st_DeleteLine[FORTIFY_DELETE_STACK_SIZE];
  164.     static unsigned long  st_DeleteStackTop;
  165. #endif /* __cplusplus */
  166.  
  167. /* statistics */
  168. static unsigned long  st_MaxBlocks        = 0;
  169. static unsigned long  st_MaxAllocation    = 0;
  170. static unsigned long  st_CurBlocks        = 0;
  171. static unsigned long  st_CurAllocation    = 0;
  172. static unsigned long  st_Allocations      = 0;
  173. static unsigned long  st_Frees            = 0;
  174. static unsigned long  st_TotalAllocation  = 0;
  175. static unsigned long  st_AllocationLimit  = 0xffffffff;
  176.  
  177. #ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
  178.     static struct Header *st_DeallocatedHead = 0;
  179.     static struct Header *st_DeallocatedTail = 0;
  180.     static unsigned long  st_TotalDeallocated = 0;
  181. #endif
  182.  
  183.  
  184. /* allocators */
  185. static const char *st_AllocatorName[] =
  186. {
  187.     "malloc()",
  188.     "calloc()",
  189.     "realloc()",
  190.     "strdup()",
  191.     "new",
  192.     "new[]"
  193. };
  194.  
  195. /* deallocators */
  196. static const char *st_DeallocatorName[] =
  197. {
  198.     "nobody",
  199.     "free()",
  200.     "realloc()",
  201.     "delete",
  202.     "delete[]"
  203. };
  204.  
  205. static const unsigned char st_ValidDeallocator[] =
  206. {
  207.     (1<<Fortify_Deallocator_free) | (1<<Fortify_Deallocator_realloc),
  208.     (1<<Fortify_Deallocator_free) | (1<<Fortify_Deallocator_realloc),
  209.     (1<<Fortify_Deallocator_free) | (1<<Fortify_Deallocator_realloc),
  210.     (1<<Fortify_Deallocator_free) | (1<<Fortify_Deallocator_realloc),
  211. #if defined(FORTIFY_PROVIDE_ARRAY_NEW) && defined(FORTIFY_PROVIDE_ARRAY_DELETE)
  212.     (1<<Fortify_Deallocator_delete),
  213.     (1<<Fortify_Deallocator_array_delete)
  214. #else
  215.     (1<<Fortify_Deallocator_delete) | (1<<Fortify_Deallocator_array_delete),
  216.     (1<<Fortify_Deallocator_delete) | (1<<Fortify_Deallocator_array_delete)
  217. #endif
  218. };
  219.  
  220.  
  221. /*
  222.  * Fortify_Allocate() - allocate a block of fortified memory
  223.  */
  224. void *FORTIFY_STORAGE
  225. Fortify_Allocate(size_t size, unsigned char allocator, const char *file, unsigned long line)
  226. {
  227.     unsigned char *ptr;
  228.     struct Header *h;
  229.     int another_try;
  230.  
  231.     /* 
  232.      * If Fortify has been disabled, then it's easy
  233.      */
  234.     if(st_Disabled)
  235.     {
  236. #ifdef FORTIFY_FAIL_ON_ZERO_MALLOC
  237.         if(size == 0 && (allocator == Fortify_Allocator_new
  238.                       || allocator == Fortify_Allocator_array_new))
  239.         {
  240.             /*
  241.              * A new of zero bytes must succeed, but a malloc of 
  242.              * zero bytes probably won't
  243.              */
  244.             return malloc(1);
  245.         }
  246. #endif
  247.  
  248.         return malloc(size);
  249.     }
  250.  
  251. #ifdef FORTIFY_CHECK_ALL_MEMORY_ON_ALLOCATE
  252.     Fortify_CheckAllMemory(file, line);
  253. #endif  
  254.  
  255.     if(st_AllocateFailRate > 0)
  256.     {
  257.         if(rand() % 100 < st_AllocateFailRate)
  258.         {
  259. #ifdef FORTIFY_WARN_ON_FALSE_FAIL
  260.             sprintf(st_Buffer, 
  261.                     "\nFortify: A \"%s\" of %lu bytes \"false failed\" at %s.%lu\n",
  262.                     st_AllocatorName[allocator], (unsigned long)size, file, line);
  263.             st_Output(st_Buffer);
  264. #endif
  265.             return(0);
  266.         }
  267.     }
  268.  
  269.     /* Check to see if this allocation will 
  270.      * push us over the artificial limit
  271.      */
  272.     if(st_CurAllocation + size > st_AllocationLimit)
  273.     {
  274. #ifdef FORTIFY_WARN_ON_FALSE_FAIL
  275.         sprintf(st_Buffer, 
  276.                 "\nFortify: A \"%s\" of %lu bytes \"false failed\" at %s.%lu\n",
  277.                 st_AllocatorName[allocator], (unsigned long)size, file, line);
  278.         st_Output(st_Buffer);
  279. #endif
  280.         return(0);
  281.     }
  282.  
  283. #ifdef FORTIFY_WARN_ON_ZERO_MALLOC
  284.     if(size == 0 && (allocator == Fortify_Allocator_malloc ||
  285.                      allocator == Fortify_Allocator_calloc ||
  286.                      allocator == Fortify_Allocator_realloc ))
  287.     {                     
  288.         sprintf(st_Buffer, 
  289.                 "\nFortify: A \"%s\" of 0 bytes attempted at %s.%lu\n",
  290.                 st_AllocatorName[allocator], file, line);
  291.            st_Output(st_Buffer);
  292.     }
  293. #endif /* FORTIFY_WARN_ON_ZERO_MALLOC */
  294.  
  295. #ifdef FORTIFY_FAIL_ON_ZERO_MALLOC
  296.     if(size == 0 && (allocator == Fortify_Allocator_malloc ||
  297.                      allocator == Fortify_Allocator_calloc ||
  298.                      allocator == Fortify_Allocator_realloc ))
  299.     {                     
  300. #ifdef FORTIFY_WARN_ON_ALLOCATE_FAIL
  301.         sprintf(st_Buffer, "\nFortify: A \"%s\" of %lu bytes failed at %s.%lu\n",
  302.                 st_AllocatorName[allocator], (unsigned long)size, file, line);
  303.         st_Output(st_Buffer);
  304. #endif /* FORTIFY_WARN_ON_ALLOCATE_FAIL */
  305.         return 0;
  306.     }
  307. #endif /* FORTIFY_FAIL_ON_ZERO_MALLOC */    
  308.  
  309. #ifdef FORTIFY_WARN_ON_SIZE_T_OVERFLOW
  310.     /*
  311.      * Ensure the size of the memory block
  312.      * plus the overhead isn't bigger than
  313.      * size_t (that'd be a drag)
  314.      */
  315.     {
  316.         size_t private_size = FORTIFY_HEADER_SIZE
  317.                             + FORTIFY_ALIGNED_BEFORE_SIZE + size + FORTIFY_AFTER_SIZE;
  318.  
  319.         if(private_size < size)
  320.         {
  321.             sprintf(st_Buffer, 
  322.                     "\nFortify: A \"%s\" of %lu bytes has overflowed size_t at %s.%lu\n",
  323.                     st_AllocatorName[allocator], (unsigned long)size, file, line);
  324.             st_Output(st_Buffer);
  325.             return(0);
  326.         }                              
  327.     }
  328. #endif                              
  329.  
  330.     another_try = 1;
  331.     do
  332.     {
  333.         /*
  334.          * malloc the memory, including the space 
  335.          * for the header and fortification buffers
  336.          */  
  337.         ptr = (unsigned char *)malloc(  FORTIFY_HEADER_SIZE
  338.                                       + FORTIFY_ALIGNED_BEFORE_SIZE 
  339.                                       + size
  340.                                       + FORTIFY_AFTER_SIZE );
  341.  
  342. #ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
  343.         /*
  344.          * If we're tracking deallocated memory, then
  345.          * we can free some of it, rather than let
  346.          * this malloc fail
  347.          */
  348.         if(!ptr)
  349.         {
  350.             another_try = st_PurgeDeallocatedBlocks(size, file, line);
  351.         }
  352. #endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
  353.  
  354.     }
  355.     while(!ptr && another_try);
  356.  
  357.     if(!ptr)
  358.     {
  359. #ifdef FORTIFY_WARN_ON_ALLOCATE_FAIL
  360.         sprintf(st_Buffer, "\nFortify: A \"%s\" of %lu bytes failed at %s.%lu\n",
  361.                 st_AllocatorName[allocator], (unsigned long)size, file, line);
  362.         st_Output(st_Buffer);
  363. #endif
  364.         return(0);       
  365.     }
  366.  
  367.     /*
  368.      * Begin Critical Region
  369.      */
  370.     FORTIFY_LOCK();
  371.  
  372.  
  373.     /* 
  374.      * Make the head's prev pointer point to us
  375.      * ('cos we're about to become the head)
  376.      */
  377.     if(st_AllocatedHead)
  378.     {
  379.         st_CheckBlock(st_AllocatedHead, file, line);
  380.         /* what should we do if this fails? (apart from panic) */
  381.  
  382.         st_AllocatedHead->Prev = (struct Header *)ptr;
  383.         st_MakeHeaderValid(st_AllocatedHead);  
  384.     }
  385.  
  386.     /*
  387.      * Initialize and validate the header
  388.      */
  389.     h = (struct Header *)ptr;
  390.     h->Size      = size;
  391.     h->File      = file;
  392.     h->Line      = line;  
  393.     h->Next      = st_AllocatedHead;
  394.     h->Prev      = 0;
  395.     h->Scope     = st_Scope;
  396.     h->Allocator = allocator;
  397.     h->Label     = 0;
  398. #ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
  399.     h->FreedFile = 0;
  400.     h->FreedLine = 0;
  401.     h->Deallocator = Fortify_Deallocator_nobody;
  402. #endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
  403.     st_MakeHeaderValid(h);
  404.     st_AllocatedHead = h;
  405.   
  406.     /*
  407.      * Initialize the fortifications
  408.      */    
  409.     st_SetFortification(ptr + FORTIFY_HEADER_SIZE,
  410.                      FORTIFY_BEFORE_VALUE, FORTIFY_ALIGNED_BEFORE_SIZE);
  411.     st_SetFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE + size,
  412.                      FORTIFY_AFTER_VALUE, FORTIFY_AFTER_SIZE);
  413.  
  414. #ifdef FORTIFY_FILL_ON_ALLOCATE
  415.     /*
  416.      * Fill the actual user memory
  417.      */
  418.     st_SetFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
  419.                         FORTIFY_FILL_ON_ALLOCATE_VALUE, size);
  420. #endif
  421.  
  422.     /*
  423.      * End Critical Region
  424.      */
  425.     FORTIFY_UNLOCK();
  426.  
  427.  
  428.     /*
  429.      * update the statistics
  430.      */
  431.     st_TotalAllocation += size;
  432.     st_Allocations++;
  433.     st_CurBlocks++;
  434.     st_CurAllocation += size;
  435.     if(st_CurBlocks > st_MaxBlocks)
  436.         st_MaxBlocks = st_CurBlocks;
  437.     if(st_CurAllocation > st_MaxAllocation)
  438.         st_MaxAllocation = st_CurAllocation;
  439.  
  440.     /*
  441.      * We return the address of the user's memory, not the start of the block,
  442.      * which points to our magic cookies
  443.      */
  444.     return(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE);
  445. }
  446.  
  447.  
  448.  
  449. /*
  450.  * Fortify_Deallocate() - Free a block of memory allocated with Fortify_Allocate()
  451.  */
  452. void FORTIFY_STORAGE
  453. Fortify_Deallocate(void *uptr, unsigned char deallocator, const char *file, unsigned long line)
  454. {
  455.     unsigned char *ptr = (unsigned char *)uptr
  456.                         - FORTIFY_HEADER_SIZE
  457.                         - FORTIFY_ALIGNED_BEFORE_SIZE;
  458.     struct Header *h   = (struct Header *)ptr;
  459.  
  460. #ifdef FORTIFY_CHECK_ALL_MEMORY_ON_DEALLOCATE
  461.     Fortify_CheckAllMemory(file, line);
  462. #endif
  463.  
  464.     /*
  465.      * If Fortify has been disabled, then it's easy
  466.      * (well, almost)
  467.      */
  468.     if(st_Disabled)
  469.     {
  470.         /* there is a possibility that this memory
  471.          * block was allocated when Fortify was
  472.          * enabled, so we must check the Allocated
  473.          * list before we free it.
  474.          */
  475.         if(!st_IsOnAllocatedList(h))
  476.         {
  477.             free(uptr);    
  478.             return;
  479.         }    
  480.         else
  481.         {
  482.             /* the block was allocated by Fortify, so we 
  483.              * gotta free it differently.
  484.              */
  485.             /*
  486.              * Begin critical region
  487.              */
  488.             FORTIFY_LOCK();
  489.         
  490.             /*
  491.              * Remove the block from the list
  492.              */
  493.             if(h->Prev)
  494.                 h->Prev->Next = h->Next;
  495.             else
  496.                 st_AllocatedHead = h->Next;
  497.         
  498.             if(h->Next)
  499.                 h->Next->Prev = h->Prev;
  500.         
  501.             /*
  502.              * End Critical Region
  503.              */
  504.             FORTIFY_UNLOCK();
  505.  
  506.             /*
  507.              * actually free the memory
  508.              */
  509.             free(ptr);
  510.             return;
  511.         }
  512.     }
  513.  
  514.  
  515. #ifdef FORTIFY_PARANOID_DEALLOCATE
  516.     if(!st_IsOnAllocatedList(h))
  517.     {
  518. #ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
  519.         if(st_IsOnDeallocatedList(h))
  520.         {
  521.             sprintf(st_Buffer, "\nFortify: \"%s\" twice of %s detected at %s.%lu\n",
  522.                                 st_DeallocatorName[deallocator],
  523.                                 st_MemoryBlockString(h), file, line);
  524.             st_Output(st_Buffer);
  525.  
  526.             sprintf(st_Buffer, "         Memory block was deallocated by \"%s\" at %s.%lu\n",
  527.                                 st_DeallocatorName[h->Deallocator], h->FreedFile, h->FreedLine);
  528.             st_Output(st_Buffer);
  529.             st_OutputDeleteTrace();
  530.             return;
  531.         }
  532. #endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
  533.  
  534. #ifdef FORTIFY_NO_PERCENT_P
  535.         sprintf(st_Buffer, "\nFortify: Possible \"%s\" twice of (0x%08lx) was detected at %s.%lu\n",
  536. #else
  537.         sprintf(st_Buffer, "\nFortify: Possible \"%s\" twice of (%p) was detected at %s.%lu\n",
  538. #endif
  539.                             st_DeallocatorName[deallocator],
  540.                             uptr, file, line);
  541.         st_Output(st_Buffer);
  542.         st_OutputDeleteTrace();
  543.         return;
  544.     }
  545. #endif /* FORTIFY_PARANOID_DELETE */
  546.  
  547.     /*
  548.      * Make sure the block is okay before we free it.
  549.      * If it's not okay, don't free it - it might not
  550.      * be a real memory block. Or worse still, someone
  551.      * might still be writing to it
  552.      */
  553.     if(!st_CheckBlock(h, file, line))
  554.     {
  555.         st_OutputDeleteTrace();
  556.         return;
  557.     }
  558.  
  559. #ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
  560.     /*
  561.      * Make sure the block hasn't been freed already
  562.      * (we can get to here if FORTIFY_PARANOID_DELETE
  563.      * is off, but FORTIFY_TRACK_DEALLOCATED_MEMORY
  564.      * is on).
  565.      */
  566.     if(h->Deallocator != Fortify_Deallocator_nobody)
  567.     {
  568.         sprintf(st_Buffer, "\nFortify: \"%s\" twice of %s detected at %s.%lu\n",
  569.                               st_DeallocatorName[deallocator],
  570.                             st_MemoryBlockString(h), file, line);
  571.         st_Output(st_Buffer);
  572.  
  573.         sprintf(st_Buffer, "         Memory block was deallocated by \"%s\" at %s.%lu\n",
  574.                             st_DeallocatorName[h->Deallocator], h->FreedFile, h->FreedLine);
  575.         st_Output(st_Buffer);
  576.         st_OutputDeleteTrace();
  577.         return;
  578.     }
  579. #endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
  580.  
  581.     /*
  582.      * Make sure the block is being freed with a valid
  583.      * deallocator. If not, complain. (but free it anyway)
  584.      */
  585.     if((st_ValidDeallocator[h->Allocator] & (1<<deallocator)) == 0)
  586.     {
  587.         sprintf(st_Buffer, "\nFortify: Incorrect deallocator \"%s\" detected at %s.%lu\n",
  588.                               st_DeallocatorName[deallocator], file, line);
  589.         st_Output(st_Buffer);
  590.         sprintf(st_Buffer,   "         %s was allocated with \"%s\"\n",
  591.                               st_MemoryBlockString(h), st_AllocatorName[h->Allocator]);
  592.         st_Output(st_Buffer);
  593.         st_OutputDeleteTrace();
  594.     }
  595.  
  596.     /*
  597.      * Begin critical region
  598.      */
  599.     FORTIFY_LOCK();
  600.  
  601.     /*
  602.      * Remove the block from the list
  603.      */
  604.     if(h->Prev)
  605.     {
  606.         if(!st_CheckBlock(h->Prev, file, line))
  607.         {
  608.             FORTIFY_UNLOCK();
  609.             st_OutputDeleteTrace();
  610.             return;
  611.         }
  612.  
  613.         h->Prev->Next = h->Next;
  614.         st_MakeHeaderValid(h->Prev);
  615.     }
  616.     else
  617.         st_AllocatedHead = h->Next;
  618.  
  619.     if(h->Next)
  620.     {
  621.         if(!st_CheckBlock(h->Next, file, line))
  622.         {
  623.             FORTIFY_UNLOCK();
  624.             st_OutputDeleteTrace();
  625.             return;
  626.         }
  627.  
  628.         h->Next->Prev = h->Prev;
  629.         st_MakeHeaderValid(h->Next);
  630.     }
  631.  
  632.     /*
  633.      * End Critical Region
  634.      */
  635.     FORTIFY_UNLOCK();
  636.  
  637.     /*
  638.      * update the statistics
  639.      */
  640.     st_Frees++;
  641.     st_CurBlocks--;
  642.     st_CurAllocation -= h->Size;
  643.  
  644.  
  645. #ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
  646.     if(st_Scope > 0)
  647.     {
  648.         /*
  649.          * Don't _actually_ free the memory block, just yet.
  650.          * Place it onto the deallocated list, instead, so
  651.          * we can check later to see if it's been written to.
  652.          */
  653.     #ifdef FORTIFY_FILL_ON_DEALLOCATE
  654.         /*
  655.          * Nuke out all user memory that is about to be freed
  656.          */
  657.         st_SetFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
  658.                                     FORTIFY_FILL_ON_DEALLOCATE_VALUE,
  659.                                   h->Size);
  660.     #endif /* FORTIFY_FILL_ON_DEALLOCATE */
  661.  
  662.         /*
  663.          * Begin critical region
  664.          */
  665.         FORTIFY_LOCK();
  666.  
  667.         /*
  668.          * Place the block on the deallocated list
  669.          */
  670.         if(st_DeallocatedHead)
  671.         {
  672.             st_DeallocatedHead->Prev = (struct Header *)ptr;
  673.             st_MakeHeaderValid(st_DeallocatedHead);
  674.         }
  675.  
  676.         h = (struct Header *)ptr;
  677.         h->FreedFile   = file;
  678.         h->FreedLine   = line;
  679.         h->Deallocator = deallocator;
  680.         h->Next        = st_DeallocatedHead;
  681.         h->Prev        = 0;
  682.         st_MakeHeaderValid(h);
  683.         st_DeallocatedHead = h;
  684.  
  685.         if(!st_DeallocatedTail)
  686.         {
  687.             st_DeallocatedTail = h;
  688.         }
  689.  
  690.         st_TotalDeallocated += h->Size;
  691.  
  692.     #ifdef FORTIFY_DEALLOCATED_MEMORY_LIMIT
  693.         /*
  694.          * If we've got too much on the deallocated list; free some
  695.          */
  696.         if(st_TotalDeallocated > FORTIFY_DEALLOCATED_MEMORY_LIMIT)
  697.         {
  698.              st_PurgeDeallocatedBlocks(st_TotalDeallocated - FORTIFY_DEALLOCATED_MEMORY_LIMIT, file, line);
  699.         }
  700.     #endif
  701.  
  702.         /*
  703.          * End critical region
  704.          */
  705.         FORTIFY_UNLOCK();
  706.     }
  707.     else
  708. #endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
  709.     {
  710.            /*
  711.          * Free the User Label
  712.          */
  713.         if(h->Label)
  714.         {
  715.             free(h->Label);
  716.         }             
  717.  
  718. #ifdef FORTIFY_FILL_ON_DEALLOCATE
  719.         /*
  720.          * Nuke out all memory that is about to be freed, including the header
  721.          */
  722.         st_SetFortification(ptr, FORTIFY_FILL_ON_DEALLOCATE_VALUE,
  723.                               FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE + h->Size + FORTIFY_AFTER_SIZE);
  724. #endif /* FORTIFY_FILL_ON_DEALLOCATE */
  725.  
  726.         /*
  727.          * And do the actual free
  728.          */
  729.         free(ptr);
  730.     }
  731. }
  732.  
  733.  
  734. /*
  735.  * Fortify_LabelPointer() - Labels the memory block
  736.  * with a string provided by the user. This function
  737.  * takes a copy of the passed in string.
  738.  * The pointer MUST be one returned by a Fortify
  739.  * allocation function.
  740.  */
  741. void
  742. Fortify_LabelPointer(void *uptr, const char *label, const char *file, unsigned long line)
  743. {
  744.     if(!st_Disabled)
  745.     {
  746.         unsigned char *ptr = (unsigned char *)uptr
  747.                               - FORTIFY_HEADER_SIZE - FORTIFY_ALIGNED_BEFORE_SIZE;
  748.         struct Header *h = (struct Header *)ptr;
  749.  
  750.         /* make sure the pointer is okay */
  751.         Fortify_CheckPointer(uptr, file, line);
  752.     
  753.         /* free the previous label */
  754.         if(h->Label)
  755.         {
  756.             free(h->Label);
  757.         }    
  758.     
  759.         /* make sure the label is sensible */
  760.         assert(label);
  761.  
  762.         /* copy it in */
  763.         h->Label = (char*)malloc(strlen(label)+1);
  764.         strcpy(h->Label, label);
  765.         
  766.         /* update the checksum */
  767.         st_MakeHeaderValid(h);
  768.     }
  769. }
  770.  
  771. /*
  772.  * Fortify_CheckPointer() - Returns true if the uptr
  773.  * points to a valid piece of Fortify_Allocated()'d
  774.  * memory. The memory must be on the allocated list,
  775.  * and it's fortifications must be intact.
  776.  * Always returns TRUE if Fortify is disabled.
  777.  */
  778. int FORTIFY_STORAGE
  779. Fortify_CheckPointer(void *uptr, const char *file, unsigned long line)
  780. {
  781.     unsigned char *ptr = (unsigned char *)uptr
  782.                               - FORTIFY_HEADER_SIZE - FORTIFY_ALIGNED_BEFORE_SIZE;
  783.     struct Header *h = (struct Header *)ptr;
  784.     int r;
  785.  
  786.     if(st_Disabled)
  787.         return 1;
  788.  
  789.     FORTIFY_LOCK();
  790.  
  791.     if(!st_IsOnAllocatedList(h))
  792.     {
  793. #ifdef FORTIFY_NO_PERCENT_P
  794.         sprintf(st_Buffer, "\nFortify: Invalid pointer (0x%08lx) detected at %s.%lu\n",
  795. #else
  796.         sprintf(st_Buffer, "\nFortify: Invalid pointer (%p) detected at %s.%lu\n",
  797. #endif
  798.                                  uptr, file, line);
  799.         st_Output(st_Buffer);
  800.         FORTIFY_UNLOCK();
  801.         return(0);
  802.     }
  803.  
  804. #ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
  805.     if(st_IsOnDeallocatedList(h))
  806.     {
  807. #ifdef FORTIFY_NO_PERCENT_P
  808.         sprintf(st_Buffer, "\nFortify: Deallocated pointer (0x%08lx) detected at %s.%lu\n",
  809. #else
  810.         sprintf(st_Buffer, "\nFortify: Deallocated pointer (%p) detected at %s.%lu\n",
  811. #endif
  812.                            uptr, file, line);
  813.         st_Output(st_Buffer);
  814.         sprintf(st_Buffer, "         Memory block was deallocated by \"%s\" at %s.%lu\n",
  815.                            st_DeallocatorName[h->Deallocator], h->FreedFile, h->FreedLine);
  816.         st_Output(st_Buffer);
  817.         FORTIFY_UNLOCK();
  818.         return(0);
  819.     }
  820. #endif
  821.  
  822.     r = st_CheckBlock(h, file, line);
  823.     FORTIFY_UNLOCK();
  824.     return r;
  825. }
  826.  
  827. /*
  828.  * Fortify_SetOutputFunc(Fortify_OutputFuncPtr Output) -
  829.  * Sets the function used to output all error and
  830.  * diagnostic messages. The output function  takes 
  831.  * a single const unsigned char * argument, and must be 
  832.  * able to handle newlines. This function returns the 
  833.  * old output function.
  834.  */
  835. Fortify_OutputFuncPtr FORTIFY_STORAGE
  836. Fortify_SetOutputFunc(Fortify_OutputFuncPtr Output)
  837. {
  838.     Fortify_OutputFuncPtr Old = st_Output;
  839.  
  840.     st_Output = Output;
  841.   
  842.     return(Old);
  843. }
  844.  
  845. /*
  846.  * Fortify_SetAllocateFailRate(int Percent) - 
  847.  * Fortify_Allocate() will "fail" this Percent of 
  848.  * the time, even if the memory is available. 
  849.  * Useful to "stress-test" an application. 
  850.  * Returns the old value.
  851.  * The fail rate defaults to 0 (a good default I think).
  852.  */
  853. int FORTIFY_STORAGE
  854. Fortify_SetAllocateFailRate(int Percent)
  855. {
  856.     int Old = st_AllocateFailRate;
  857.   
  858.     st_AllocateFailRate = Percent;
  859.   
  860.     return(Old);
  861. }
  862.  
  863.  
  864. /*
  865.  * Fortify_CheckAllMemory() - Checks the fortifications
  866.  * of all memory on the allocated list. And, if 
  867.  * FORTIFY_DEALLOCATED_MEMORY is enabled, all the
  868.  * known deallocated memory as well.
  869.  * Returns the number of blocks that failed. 
  870.  * Always returns 0 if Fortify is disabled.
  871.  */
  872. unsigned long FORTIFY_STORAGE
  873. Fortify_CheckAllMemory(const char *file, unsigned long line)
  874. {
  875.     struct Header *curr = st_AllocatedHead;
  876.     unsigned long count = 0;
  877.  
  878.     if(st_Disabled)
  879.         return 0;
  880.  
  881.     FORTIFY_LOCK();
  882.  
  883.     /*
  884.      * Check the allocated memory
  885.      */ 
  886.     while(curr)
  887.     {
  888.         if(!st_CheckBlock(curr, file, line))
  889.             count++;
  890.  
  891.         curr = curr->Next;      
  892.     }
  893.  
  894.     /*
  895.      * Check the deallocated memory while you're at it
  896.      */
  897. #ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
  898.     curr = st_DeallocatedHead;
  899.     while(curr)
  900.     {
  901.         if(!st_CheckDeallocatedBlock(curr, file, line))
  902.             count++;
  903.  
  904.         curr = curr->Next;      
  905.     }
  906. #endif    
  907.  
  908.     /*  
  909.      * If we know where we are, and everything is cool,
  910.      * remember that. It might be important.
  911.      */
  912.     if(file && count == 0)
  913.     {
  914.         st_LastVerifiedFile = file;
  915.         st_LastVerifiedLine = line;
  916.     }
  917.  
  918.     FORTIFY_UNLOCK();
  919.     return(count);
  920. }
  921.  
  922.  
  923. /*
  924.  * Fortify_EnterScope() - enters a new Fortify scope 
  925.  * level. Returns the new scope level.
  926.  */
  927. unsigned char FORTIFY_STORAGE
  928. Fortify_EnterScope(const char *file, unsigned long line)
  929. {
  930.     return(++st_Scope);
  931. }
  932.  
  933. /* Fortify_LeaveScope - leaves a Fortify scope level,
  934.  * also prints a memory dump of all non-freed memory 
  935.  * that was allocated during the scope being exited.
  936.  * Does nothing and returns 0 if Fortify is disabled.
  937.  */
  938. unsigned char FORTIFY_STORAGE
  939. Fortify_LeaveScope(const char *file, unsigned long line)
  940. {
  941.     struct Header *curr = st_AllocatedHead;
  942.     unsigned long size = 0, count = 0;
  943.  
  944.     if(st_Disabled)
  945.         return 0;
  946.  
  947.     FORTIFY_LOCK();
  948.  
  949.     st_Scope--;
  950.     while(curr)
  951.     {
  952.         if(curr->Scope > st_Scope)
  953.         {
  954.             if(count == 0)
  955.             {
  956.                 sprintf(st_Buffer, "\nFortify: Memory leak detected leaving scope at %s.%lu\n", file, line);
  957.                 st_Output(st_Buffer);
  958.                 sprintf(st_Buffer, "%10s %8s %s\n", "Address", "Size", "Allocator");
  959.                 st_Output(st_Buffer);
  960.             }
  961.             
  962.             st_OutputHeader(curr);
  963.             count++;
  964.             size += curr->Size;
  965.         }
  966.  
  967.         curr = curr->Next;      
  968.     }
  969.  
  970.     if(count)
  971.     {
  972.         sprintf(st_Buffer,"%10s %8lu bytes in %lu blocks with %lu bytes overhead\n", 
  973.                 "total", size, count, count * FORTIFY_OVERHEAD);
  974.         st_Output(st_Buffer);
  975.     }
  976.  
  977. #ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
  978.     /* 
  979.      * Quietly free all the deallocated memory 
  980.      * that was allocated in this scope that 
  981.      * we are still tracking
  982.      */
  983.     st_PurgeDeallocatedScope( st_Scope, file, line );
  984. #endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
  985.  
  986.     FORTIFY_UNLOCK();
  987.     return(st_Scope);
  988. }
  989.  
  990. /*
  991.  * Fortify_ListAllMemory() - Outputs the entire 
  992.  * list of currently allocated memory. For each block 
  993.  * is output it's Address, Size, and the SourceFile and 
  994.  * Line that allocated it.
  995.  *
  996.  * If there is no memory on the list, this function 
  997.  * outputs nothing.
  998.  *
  999.  * It returns the number of blocks on the list, unless 
  1000.  * Fortify has been disabled, in which case it always 
  1001.  * returns 0.
  1002.  */
  1003. unsigned long FORTIFY_STORAGE
  1004. Fortify_ListAllMemory(const char *file, unsigned long line)
  1005. {
  1006.     struct Header *curr = st_AllocatedHead;
  1007.     unsigned long size = 0, count = 0;
  1008.  
  1009.     if(st_Disabled)
  1010.         return 0;
  1011.  
  1012.     Fortify_CheckAllMemory(file, line);
  1013.  
  1014.     FORTIFY_LOCK();
  1015.  
  1016.     if(curr)
  1017.     {
  1018.         sprintf(st_Buffer, "\nFortify: Memory List at %s.%lu\n", file, line);
  1019.         st_Output(st_Buffer);
  1020.         sprintf(st_Buffer, "%10s %8s %s\n", "Address", "Size", "Allocator");
  1021.         st_Output(st_Buffer);
  1022.                                 
  1023.         while(curr)
  1024.         {
  1025.             st_OutputHeader(curr);
  1026.             count++;
  1027.             size += curr->Size;
  1028.             curr = curr->Next;      
  1029.         }
  1030.                      
  1031.         sprintf(st_Buffer, "%10s %8lu bytes in %lu blocks and %lu bytes overhead\n", 
  1032.                            "total", size, count, count * FORTIFY_OVERHEAD);
  1033.         st_Output(st_Buffer);
  1034.     }
  1035.   
  1036.     FORTIFY_UNLOCK();
  1037.     return(count);
  1038. }
  1039.  
  1040. /*
  1041.  * Fortify_DumpAllMemory() - Outputs the entire list of 
  1042.  * currently allocated memory. For each allocated block 
  1043.  * is output it's Address, Size, the SourceFile and Line
  1044.  * that allocated it, a hex dump of the contents of the 
  1045.  * memory and an ascii dump of printable characters.
  1046.  *
  1047.  * If there is no memory on the list, this function outputs nothing.
  1048.  */
  1049. unsigned long FORTIFY_STORAGE
  1050. Fortify_DumpAllMemory(const char *file, unsigned long line)
  1051. {
  1052.     struct Header *curr = st_AllocatedHead;
  1053.     unsigned long count = 0;
  1054.  
  1055.     if(st_Disabled)
  1056.         return 0;
  1057.  
  1058.     Fortify_CheckAllMemory(file, line);
  1059.  
  1060.     FORTIFY_LOCK();
  1061.  
  1062.     while(curr)
  1063.     {
  1064.         sprintf(st_Buffer, "\nFortify: Hex Dump of %s at %s.%lu\n",
  1065.                 st_MemoryBlockString(curr), file, line);
  1066.         st_Output(st_Buffer);
  1067.         st_OutputMemory(curr);
  1068.         st_Output("\n");
  1069.         count++;
  1070.  
  1071.         curr = curr->Next;
  1072.     }
  1073.  
  1074.     FORTIFY_UNLOCK();
  1075.     return(count);
  1076. }
  1077.  
  1078. /* Fortify_OutputStatistics() - displays statistics 
  1079.  * about the maximum amount of memory that was 
  1080.  * allocated at any one time.
  1081.  */
  1082. void FORTIFY_STORAGE
  1083. Fortify_OutputStatistics(const char *file, unsigned long line)
  1084. {
  1085.     if(st_Disabled)
  1086.         return;
  1087.  
  1088.     sprintf(st_Buffer, "\nFortify: Statistics at %s.%lu\n", file, line);
  1089.     st_Output(st_Buffer);
  1090.  
  1091.     sprintf(st_Buffer, "         Memory currently allocated: %lu bytes in %lu blocks\n",
  1092.                                  st_CurAllocation, st_CurBlocks);
  1093.     st_Output(st_Buffer);
  1094.     sprintf(st_Buffer, "         Maximum memory allocated at one time: %lu bytes in %lu blocks\n", 
  1095.                                  st_MaxAllocation, st_MaxBlocks);
  1096.     st_Output(st_Buffer);
  1097.     sprintf(st_Buffer, "         There have been %lu allocations and %lu deallocations\n",
  1098.                                  st_Allocations, st_Frees);
  1099.     st_Output(st_Buffer);
  1100.     sprintf(st_Buffer, "         There was a total of %lu bytes allocated\n",
  1101.                                  st_TotalAllocation);
  1102.     st_Output(st_Buffer);
  1103.     
  1104.     if(st_Allocations > 0)
  1105.     {
  1106.         sprintf(st_Buffer, "         The average allocation was %lu bytes\n",
  1107.                                      st_TotalAllocation / st_Allocations);
  1108.         st_Output(st_Buffer);                   
  1109.     }    
  1110. }
  1111.  
  1112. /* Fortify_GetCurrentAllocation() - returns the number of
  1113.  * bytes currently allocated.
  1114.  */
  1115. unsigned long FORTIFY_STORAGE
  1116. Fortify_GetCurrentAllocation(const char *file, unsigned long line)
  1117. {
  1118.     if(st_Disabled)
  1119.         return 0;
  1120.  
  1121.     return st_CurAllocation;
  1122. }
  1123.  
  1124. /* Fortify_SetAllocationLimit() - set a limit on the total
  1125.  * amount of memory allowed for this application.
  1126.  */
  1127. void FORTIFY_STORAGE
  1128. Fortify_SetAllocationLimit(unsigned long NewLimit, const char *file, unsigned long line)
  1129. {
  1130.     st_AllocationLimit = NewLimit;
  1131. }
  1132.  
  1133. /*
  1134.  * Fortify_Disable() - Run time method of disabling Fortify.
  1135.  * Useful if you need to turn off Fortify without recompiling
  1136.  * everything. Not as effective as compiling out, of course.
  1137.  * The less memory allocated by Fortify when it is disabled
  1138.  * the better.
  1139.  * (Previous versions of Fortify did not allow it to be 
  1140.  * disabled if there was any memory allocated at the time,
  1141.  * but since in C++ memory is often allocated before main
  1142.  * is even entered, this was useless so Fortify is now
  1143.  * able to cope).
  1144.  */
  1145. void FORTIFY_STORAGE
  1146. Fortify_Disable(const char *file, unsigned long line)
  1147. {
  1148. #ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
  1149.     /* free all deallocated memory we might be tracking */
  1150.     st_PurgeDeallocatedScope( 0, file, line );
  1151. #endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
  1152.  
  1153.     st_Disabled = 1;
  1154. }
  1155.  
  1156.  
  1157.  
  1158. /*
  1159.  * st_CheckBlock - Check a block's header and fortifications.
  1160.  * Returns true if the block is happy.
  1161.  */
  1162. static int
  1163. st_CheckBlock(struct Header *h, const char *file, unsigned long line)
  1164. {
  1165.     unsigned char *ptr = (unsigned char *)h;
  1166.     int result = 1;
  1167.  
  1168.     if(!st_IsHeaderValid(h))
  1169.     {
  1170.         sprintf(st_Buffer,
  1171. #ifdef FORTIFY_NO_PERCENT_P
  1172.                 "\nFortify: Invalid pointer (0x%08lx) or corrupted header detected at %s.%lu\n",
  1173. #else
  1174.                 "\nFortify: Invalid pointer (%p) or corrupted header detected at %s.%lu\n",
  1175. #endif
  1176.                 ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE, file, line);
  1177.         st_Output(st_Buffer);
  1178.         st_OutputLastVerifiedPoint();
  1179.         return(0);
  1180.     }
  1181.  
  1182.     if(!st_CheckFortification(ptr + FORTIFY_HEADER_SIZE,
  1183.                            FORTIFY_BEFORE_VALUE, FORTIFY_ALIGNED_BEFORE_SIZE))
  1184.     {
  1185.         sprintf(st_Buffer, "\nFortify: Underwrite detected before block %s at %s.%lu\n",
  1186.                            st_MemoryBlockString(h), file, line);
  1187.         st_Output(st_Buffer);
  1188.  
  1189.         st_OutputLastVerifiedPoint();
  1190.         st_OutputFortification(ptr + FORTIFY_HEADER_SIZE,
  1191.                             FORTIFY_BEFORE_VALUE, FORTIFY_ALIGNED_BEFORE_SIZE);
  1192.         result = 0;                        
  1193.  
  1194. #ifdef FORTIFY_FILL_ON_CORRUPTION
  1195.         st_SetFortification(ptr + FORTIFY_HEADER_SIZE, FORTIFY_BEFORE_VALUE, FORTIFY_ALIGNED_BEFORE_SIZE);
  1196. #endif
  1197.     }
  1198.                            
  1199.     if(!st_CheckFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE + h->Size,
  1200.                            FORTIFY_AFTER_VALUE, FORTIFY_AFTER_SIZE))
  1201.     {
  1202.         sprintf(st_Buffer, "\nFortify: Overwrite detected after block %s at %s.%lu\n",
  1203.                            st_MemoryBlockString(h), file, line);
  1204.         st_Output(st_Buffer);
  1205.  
  1206.         st_OutputLastVerifiedPoint();
  1207.         st_OutputFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE + h->Size,
  1208.                             FORTIFY_AFTER_VALUE, FORTIFY_AFTER_SIZE);
  1209.         result = 0;
  1210.  
  1211. #ifdef FORTIFY_FILL_ON_CORRUPTION
  1212.         st_SetFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE + h->Size,
  1213.                          FORTIFY_AFTER_VALUE, FORTIFY_AFTER_SIZE);
  1214. #endif
  1215.     }
  1216.  
  1217.     return(result);    
  1218. }
  1219.  
  1220. #ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
  1221.  
  1222. /* 
  1223.  * st_CheckDeallocatedBlock - Check a deallocated block's header and fortifications.
  1224.  * Returns true if the block is happy.
  1225.  */
  1226. static int  
  1227. st_CheckDeallocatedBlock(struct Header *h, const char *file, unsigned long line)
  1228. {
  1229.     unsigned char *ptr = (unsigned char *)h;
  1230.     int result = 1;
  1231.  
  1232.     if(!st_IsHeaderValid(h))
  1233.     {
  1234.         sprintf(st_Buffer,
  1235. #ifdef FORTIFY_NO_PERCENT_P
  1236.                 "\nFortify: Invalid deallocated pointer (0x%08lx) or corrupted header detected at %s.%lu\n",
  1237. #else
  1238.                 "\nFortify: Invalid deallocated pointer (%p) or corrupted header detected at %s.%lu\n",
  1239. #endif
  1240.                 ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE, file, line);
  1241.         st_Output(st_Buffer);
  1242.         st_OutputLastVerifiedPoint();
  1243.         return(0);
  1244.     }
  1245.  
  1246.     if(!st_CheckFortification(ptr + FORTIFY_HEADER_SIZE,
  1247.                            FORTIFY_BEFORE_VALUE, FORTIFY_ALIGNED_BEFORE_SIZE))
  1248.     {
  1249.         sprintf(st_Buffer, "\nFortify: Underwrite detected before deallocated block %s at %s.%lu\n",
  1250.                            st_MemoryBlockString(h), file, line);
  1251.         st_Output(st_Buffer);
  1252.         sprintf(st_Buffer, "         Memory block was deallocated by \"%s\" at %s.%lu\n",
  1253.                            st_DeallocatorName[h->Deallocator], h->FreedFile, h->FreedLine);
  1254.         st_Output(st_Buffer);
  1255.  
  1256.         st_OutputLastVerifiedPoint();
  1257.         st_OutputFortification(ptr + FORTIFY_HEADER_SIZE,
  1258.                             FORTIFY_BEFORE_VALUE, FORTIFY_ALIGNED_BEFORE_SIZE);
  1259.  
  1260. #ifdef FORTIFY_FILL_ON_CORRUPTION
  1261.         st_SetFortification(ptr + FORTIFY_HEADER_SIZE, FORTIFY_BEFORE_VALUE, FORTIFY_ALIGNED_BEFORE_SIZE);
  1262. #endif
  1263.         result = 0;
  1264.     }
  1265.                            
  1266.     if(!st_CheckFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE + h->Size,
  1267.                            FORTIFY_AFTER_VALUE, FORTIFY_AFTER_SIZE))
  1268.     {
  1269.         sprintf(st_Buffer, "\nFortify: Overwrite detected after deallocated block %s at %s.%lu\n",
  1270.                            st_MemoryBlockString(h), file, line);
  1271.         st_Output(st_Buffer);
  1272.         sprintf(st_Buffer, "         Memory block was deallocated by \"%s\" at %s.%lu\n",
  1273.                            st_DeallocatorName[h->Deallocator], h->FreedFile, h->FreedLine);
  1274.         st_Output(st_Buffer);
  1275.  
  1276.         st_OutputLastVerifiedPoint();
  1277.         st_OutputFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE + h->Size,
  1278.                             FORTIFY_AFTER_VALUE, FORTIFY_AFTER_SIZE);
  1279.  
  1280. #ifdef FORTIFY_FILL_ON_CORRUPTION
  1281.         st_SetFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE + h->Size,
  1282.                          FORTIFY_AFTER_VALUE, FORTIFY_AFTER_SIZE);
  1283. #endif
  1284.         result = 0;
  1285.     }
  1286.  
  1287. #ifdef FORTIFY_FILL_ON_DEALLOCATE
  1288.     if(!st_CheckFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
  1289.                            FORTIFY_FILL_ON_DEALLOCATE_VALUE, h->Size))
  1290.     {
  1291.         sprintf(st_Buffer, "\nFortify: Write to deallocated block %s detected at %s.%lu\n",
  1292.                            st_MemoryBlockString(h), file, line);
  1293.         st_Output(st_Buffer);
  1294.  
  1295.         sprintf(st_Buffer, "         Memory block was deallocated by \"%s\" at %s.%lu\n",
  1296.                            st_DeallocatorName[h->Deallocator], h->FreedFile, h->FreedLine);
  1297.         st_Output(st_Buffer);
  1298.         st_OutputLastVerifiedPoint();
  1299.     
  1300.         st_OutputFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
  1301.                             FORTIFY_FILL_ON_DEALLOCATE_VALUE, h->Size);
  1302.  
  1303. #ifdef FORTIFY_FILL_ON_CORRUPTION
  1304.         st_SetFortification(ptr + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
  1305.                             FORTIFY_FILL_ON_DEALLOCATE_VALUE, h->Size);
  1306. #endif /* FORTIFY_FILL_ON_CORRUPTION */
  1307.         result = 0;
  1308.     }
  1309. #endif /* FORTIFY_FILL_ON_DEALLOCATE */
  1310.     return result;
  1311.  }
  1312.  
  1313. #endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
  1314.  
  1315.  
  1316. /*
  1317.  * st_CheckFortification - Checks if the _size_ 
  1318.  * bytes from _ptr_ are all set to _value_
  1319.  * Returns true if all is happy.
  1320.  */
  1321. static int 
  1322. st_CheckFortification(unsigned char *ptr, unsigned char value, size_t size)
  1323. {
  1324.     while(size--)
  1325.         if(*ptr++ != value)
  1326.             return(0);
  1327.       
  1328.     return(1);      
  1329. }
  1330.  
  1331. /*
  1332.  * st_SetFortification - Set the _size_ bytes from _ptr_ to _value_.
  1333.  */
  1334. static void 
  1335. st_SetFortification(unsigned char *ptr, unsigned char value, size_t size)
  1336. {
  1337.     memset(ptr, value, size);
  1338. }
  1339.  
  1340. /*
  1341.  * st_OutputFortification - Output the corrupted section of the fortification 
  1342.  */
  1343. static void
  1344. st_OutputFortification(unsigned char *ptr, unsigned char value, size_t size)
  1345. {
  1346.     size_t offset, skipped, advance;
  1347.     offset = 0;
  1348.  
  1349.     sprintf(st_Buffer, "   Address   Offset Data (%02x)", value);
  1350.     st_Output(st_Buffer);
  1351.  
  1352.     while(offset < size)
  1353.     {
  1354.         /* 
  1355.          * Skip 3 or more 'correct' lines
  1356.          */
  1357.         if((size - offset) < 3 * 16)             
  1358.             advance = size - offset;
  1359.         else
  1360.             advance = 3 * 16;
  1361.         if(advance > 0 && st_CheckFortification(ptr+offset, value, advance))
  1362.         {
  1363.             offset += advance;
  1364.             skipped = advance;
  1365.                  
  1366.             if(size - offset < 16)             
  1367.                 advance = size - offset;
  1368.             else
  1369.                 advance = 16;
  1370.              
  1371.             while(advance > 0 && st_CheckFortification(ptr+offset, value, advance))
  1372.             {
  1373.                 offset  += advance;
  1374.                 skipped += advance;
  1375.                 if(size - offset < 16)             
  1376.                     advance = size - offset;
  1377.                 else
  1378.                     advance = 16;
  1379.             }    
  1380.             sprintf(st_Buffer, "\n                        ...%lu bytes skipped...", (unsigned long)skipped);
  1381.             st_Output(st_Buffer);
  1382.             continue;
  1383.         }
  1384.         else
  1385.         {
  1386.             if(size - offset < 16)
  1387.                 st_HexDump(ptr, offset, size-offset, 0);
  1388.             else
  1389.                 st_HexDump(ptr, offset, 16, 0);
  1390.                 
  1391.             offset += 16;
  1392.         }
  1393.     }
  1394.  
  1395.     st_Output("\n");
  1396. }
  1397.  
  1398. /*
  1399.  * st_HexDump - output a nice hex dump of "size" bytes, starting at "ptr" + "offset"
  1400.  */
  1401. static void
  1402. st_HexDump(unsigned char *ptr, size_t offset, size_t size, int title)
  1403. {
  1404.     char ascii[17];
  1405.     int  column;
  1406.     int  output;
  1407.  
  1408.     if(title)
  1409.         st_Output("   Address   Offset Data");
  1410.  
  1411.     column = 0;
  1412.     ptr += offset;
  1413.     output = 0;
  1414.  
  1415.     while(output < size)
  1416.     {
  1417.         if(column == 0)
  1418.         {
  1419. #ifdef FORTIFY_NO_PERCENT_P
  1420.             sprintf(st_Buffer, "\n0x%08lx %8lu ", ptr, (unsigned long)offset);
  1421. #else
  1422.             sprintf(st_Buffer, "\n%10p %8lu ", ptr, (unsigned long)offset);
  1423. #endif
  1424.             st_Output(st_Buffer);
  1425.         }
  1426.  
  1427.         sprintf(st_Buffer, "%02x%s", *ptr, ((column % 4) == 3) ? " " : "");
  1428.         st_Output(st_Buffer);
  1429.  
  1430.         ascii[ column ] = isprint( *ptr ) ? (char)(*ptr) : (char)('.');
  1431.         ascii[ column + 1 ] = '\0';
  1432.  
  1433.         ptr++;
  1434.         offset++;
  1435.         output++;
  1436.         column++;
  1437.  
  1438.         if(column == 16)
  1439.         {
  1440.             st_Output( "   \"" );
  1441.             st_Output( ascii );
  1442.             st_Output( "\"" );
  1443.             column = 0;
  1444.         }
  1445.     }
  1446.  
  1447.     if ( column != 0 )
  1448.     {
  1449.         while ( column < 16 )
  1450.         {
  1451.             if( column % 4 == 3 )
  1452.                 st_Output( "   " );
  1453.             else
  1454.                 st_Output( "  " );
  1455.  
  1456.             column++;
  1457.         }
  1458.         st_Output( "   \"" );
  1459.         st_Output( ascii );
  1460.         st_Output( "\"" );
  1461.     }
  1462. }
  1463.  
  1464. /*
  1465.  * st_IsHeaderValid - Returns true if the 
  1466.  * supplied pointer does indeed point to a 
  1467.  * real Header
  1468.  */
  1469. static int 
  1470. st_IsHeaderValid(struct Header *h)                                
  1471. {
  1472.     return(st_ChecksumHeader(h) == FORTIFY_CHECKSUM_VALUE);
  1473. }
  1474.  
  1475. /*
  1476.  * st_MakeHeaderValid - Updates the checksum 
  1477.  * to make the header valid
  1478.  */
  1479. static void 
  1480. st_MakeHeaderValid(struct Header *h)
  1481. {
  1482.     h->Checksum = 0;
  1483.     h->Checksum = (unsigned short)(FORTIFY_CHECKSUM_VALUE - st_ChecksumHeader(h));
  1484. }
  1485.  
  1486. /*
  1487.  * st_ChecksumHeader - Calculate (and return) 
  1488.  * the checksum of the header. (Including the 
  1489.  * Checksum field itself. If all is well, the 
  1490.  * checksum returned by this function should
  1491.  * be FORTIFY_CHECKSUM_VALUE
  1492.  */
  1493. static unsigned short
  1494. st_ChecksumHeader(struct Header *h)
  1495. {
  1496.     unsigned short c, checksum, *p;
  1497.   
  1498.     for(c = 0, checksum = 0, p = (unsigned short *)h; 
  1499.         c < FORTIFY_HEADER_SIZE/sizeof(unsigned short); c++)
  1500.     {    
  1501.         checksum += *p++;  
  1502.     }    
  1503.     
  1504.     return(checksum);
  1505. }                  
  1506.  
  1507. /* 
  1508.  * st_IsOnAllocatedList - Examines the allocated 
  1509.  * list to see if the given header is on it.
  1510.  */  
  1511. static int 
  1512. st_IsOnAllocatedList(struct Header *h)
  1513. {
  1514.     struct Header *curr;
  1515.   
  1516.     curr = st_AllocatedHead;
  1517.     while(curr)
  1518.     {
  1519.         if(curr == h)
  1520.             return(1);
  1521.       
  1522.         curr = curr->Next;
  1523.     }
  1524.   
  1525.     return(0);
  1526. }
  1527.  
  1528. #ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
  1529. /* 
  1530.  * st_IsOnDeallocatedList - Examines the deallocated 
  1531.  * list to see if the given header is on it.
  1532.  */  
  1533. static int 
  1534. st_IsOnDeallocatedList(struct Header *h)
  1535. {
  1536.     struct Header *curr;
  1537.   
  1538.     curr = st_DeallocatedHead;
  1539.     while(curr)
  1540.     {
  1541.         if(curr == h)
  1542.             return(1);
  1543.       
  1544.         curr = curr->Next;
  1545.     }
  1546.   
  1547.     return(0);
  1548. }
  1549.  
  1550. /*
  1551.  * st_PurgeDeallocatedBlocks - free at least "Bytes"
  1552.  * worth of deallocated memory, starting at the 
  1553.  * oldest deallocated block.
  1554.  * Returns true if any blocks were freed.
  1555.  */
  1556. static int
  1557. st_PurgeDeallocatedBlocks(unsigned long Bytes, const char *file, unsigned long line)
  1558. {
  1559.     unsigned long FreedBytes = 0;
  1560.     unsigned long FreedBlocks = 0;
  1561.  
  1562. #ifdef FORTIFY_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY
  1563.     sprintf(st_Buffer, "\nFortify: Warning - Discarding deallocated memory at %s.%lu\n", 
  1564.                        file, line);
  1565.     st_Output(st_Buffer);
  1566. #endif /* FORTIFY_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY */
  1567.  
  1568.     while(st_DeallocatedTail && FreedBytes < Bytes)
  1569.     {
  1570.         st_CheckDeallocatedBlock(st_DeallocatedTail, file, line);
  1571.         FreedBytes += st_DeallocatedTail->Size;
  1572.         FreedBlocks++;
  1573. #ifdef FORTIFY_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY
  1574. #ifdef FORTIFY_VERBOSE_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY
  1575.         sprintf(st_Buffer, "                %s\n",
  1576.                            st_DeallocatedMemoryBlockString(st_DeallocatedTail));
  1577.         st_Output(st_Buffer);
  1578. #endif /* FORTIFY_VERBOSE_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY */
  1579. #endif /* FORTIFY_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY */
  1580.         st_FreeDeallocatedBlock(st_DeallocatedTail, file, line);
  1581.     }
  1582.  
  1583.     return FreedBlocks != 0;
  1584. }
  1585.  
  1586. /*
  1587.  * st_PurgeDeallocatedScope - free all deallocated
  1588.  * memory blocks that were allocated within "Scope"
  1589.  */
  1590. static int
  1591. st_PurgeDeallocatedScope(unsigned char Scope, const char *file, unsigned long line)
  1592. {
  1593.     struct Header *curr, *next;
  1594.     unsigned long FreedBlocks = 0;
  1595.  
  1596.     curr = st_DeallocatedHead;
  1597.     while(curr)
  1598.     {
  1599.         next = curr->Next;
  1600.         if(curr->Scope >= Scope)
  1601.         {
  1602.             st_FreeDeallocatedBlock(curr, file, line);
  1603.             FreedBlocks++;
  1604.         }
  1605.  
  1606.         curr = next;
  1607.     }
  1608.     
  1609.     return FreedBlocks != 0;
  1610. }
  1611.  
  1612. /*
  1613.  * st_FreeDeallocatedBlock - actually remove
  1614.  * a deallocated block from the deallocated 
  1615.  * list, and actually free it's memory.
  1616.  */
  1617. static void
  1618. st_FreeDeallocatedBlock(struct Header *h, const char *file, unsigned long line)
  1619. {
  1620.     st_CheckDeallocatedBlock( h, file, line );
  1621.  
  1622.    /* 
  1623.     * Begin Critical region 
  1624.     */
  1625.     FORTIFY_LOCK();
  1626.  
  1627.     st_TotalDeallocated -= h->Size;
  1628.     
  1629.     if(st_DeallocatedHead == h)
  1630.     {
  1631.         st_DeallocatedHead = h->Next;
  1632.     }
  1633.     
  1634.     if(st_DeallocatedTail == h)
  1635.     {
  1636.         st_DeallocatedTail = h->Prev;
  1637.     }
  1638.     
  1639.     if(h->Prev)
  1640.     {
  1641.         st_CheckDeallocatedBlock(h->Prev, file, line);
  1642.         h->Prev->Next = h->Next;
  1643.         st_MakeHeaderValid(h->Prev);    
  1644.     }
  1645.     
  1646.     if(h->Next)
  1647.     {
  1648.         st_CheckDeallocatedBlock(h->Next, file, line);
  1649.         h->Next->Prev = h->Prev;
  1650.         st_MakeHeaderValid(h->Next);    
  1651.     }
  1652.  
  1653.     /*
  1654.      * Free the label
  1655.      */
  1656.     if(h->Label) 
  1657.     {
  1658.         free(h->Label);
  1659.     }
  1660.  
  1661.     /*
  1662.      * Nuke out all memory that is about to be freed, including the header
  1663.      */
  1664.     st_SetFortification((unsigned char*)h, FORTIFY_FILL_ON_DEALLOCATE_VALUE,
  1665.                         FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE + h->Size + FORTIFY_AFTER_SIZE);
  1666.  
  1667.     /*
  1668.      * And do the actual free
  1669.      */
  1670.     free(h);
  1671.     
  1672.     /*
  1673.      * End critical region
  1674.      */
  1675.     FORTIFY_UNLOCK();    
  1676. }
  1677.  
  1678. #endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
  1679.  
  1680. /*
  1681.  * st_OutputMemory - Hex and ascii dump the 
  1682.  * user memory of a block.
  1683.  */
  1684. static void
  1685. st_OutputMemory(struct Header *h)
  1686. {
  1687.     st_HexDump((unsigned char*)h + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
  1688.                0, h->Size, 1);
  1689. }
  1690.  
  1691.  
  1692. /*
  1693.  * st_OutputHeader - Output the header
  1694.  */
  1695. static void 
  1696. st_OutputHeader(struct Header *h)
  1697. {
  1698.     if(h->Label == NULL)
  1699.     {
  1700. #ifdef FORTIFY_NO_PERCENT_P
  1701.         sprintf(st_Buffer, "0x%08lx %8lu %s.%lu\n", 
  1702. #else
  1703.         sprintf(st_Buffer, "%10p %8lu %s.%lu\n", 
  1704. #endif
  1705.                            (unsigned char*)h + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
  1706.                            (unsigned long)h->Size,
  1707.                            h->File, h->Line);
  1708.     }                   
  1709.     else
  1710.     {
  1711. #ifdef FORTIFY_NO_PERCENT_P
  1712.         sprintf(st_Buffer, "0x%08lx %8lu %s.%lu %s\n", 
  1713. #else
  1714.         sprintf(st_Buffer, "%10p %8lu %s.%lu %s\n", 
  1715. #endif
  1716.                            (unsigned char*)h + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
  1717.                            (unsigned long)h->Size,
  1718.                            h->File, h->Line, h->Label);
  1719.     }
  1720.     st_Output(st_Buffer);
  1721. }
  1722.  
  1723. /*
  1724.  * st_OutputLastVerifiedPoint - output the last
  1725.  * known point where everything was hoopy.
  1726.  */
  1727. static void 
  1728. st_OutputLastVerifiedPoint()
  1729. {
  1730.     sprintf(st_Buffer, "         Memory integrity was last verified at %s.%lu\n", 
  1731.                        st_LastVerifiedFile,
  1732.                        st_LastVerifiedLine);
  1733.     st_Output(st_Buffer);
  1734. }
  1735.  
  1736. /*
  1737.  * st_MemoryBlockString - constructs a string that 
  1738.  * desribes a memory block. (pointer,size,allocator,label)
  1739.  */
  1740. static const char *
  1741. st_MemoryBlockString(struct Header *h)
  1742. {
  1743.     static char st_BlockString[512];
  1744.     
  1745.     if(h->Label == 0)
  1746.     {
  1747. #ifdef FORTIFY_NO_PERCENT_P
  1748.         sprintf(st_BlockString,"(0x%08lx,%lu,%s.%lu)",
  1749. #else
  1750.         sprintf(st_BlockString,"(%p,%lu,%s.%lu)",
  1751. #endif
  1752.                 (char*)h + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
  1753.                 (unsigned long)h->Size, h->File, h->Line);
  1754.     }            
  1755.     else
  1756.     {
  1757. #ifdef FORTIFY_NO_PERCENT_P
  1758.         sprintf(st_BlockString,"(0x%08lx,%lu,%s.%lu,%s)",
  1759. #else
  1760.         sprintf(st_BlockString,"(%p,%lu,%s.%lu,%s)",
  1761. #endif
  1762.                 (char*)h + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
  1763.                 (unsigned long)h->Size, h->File, h->Line, h->Label);
  1764.     }
  1765.  
  1766.     return st_BlockString;
  1767. }
  1768.  
  1769. #ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
  1770. #ifdef FORTIFY_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY
  1771. #ifdef FORTIFY_VERBOSE_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY
  1772. /*
  1773.  * st_DeallocatedMemoryBlockString - constructs
  1774.  * a string that desribes a deallocated memory
  1775.  * block. (pointer,size,allocator,deallocator)
  1776.  */
  1777.  
  1778. static const char *
  1779. st_DeallocatedMemoryBlockString(struct Header *h)
  1780. {
  1781.     static char st_BlockString[256];
  1782.  
  1783.     if(h->Label == 0)
  1784.     {
  1785. #ifdef FORTIFY_NO_PERCENT_P
  1786.         sprintf(st_BlockString,"(0x%08lx,%lu,%s.%lu,%s.%lu)",
  1787. #else
  1788.         sprintf(st_BlockString,"(%p,%lu,%s.%lu,%s.%lu)",
  1789. #endif
  1790.                 (char*)h + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
  1791.                 (unsigned long)h->Size, h->File, h->Line, h->FreedFile, h->FreedLine);
  1792.     }            
  1793.     else
  1794.     {
  1795. #ifdef FORTIFY_NO_PERCENT_P
  1796.         sprintf(st_BlockString,"(0x%08lx,%lu,%s.%lu,%s.%lu,%s)",
  1797. #else
  1798.         sprintf(st_BlockString,"(%p,%lu,%s.%lu,%s.%lu,%s)",
  1799. #endif
  1800.                 (char*)h + FORTIFY_HEADER_SIZE + FORTIFY_ALIGNED_BEFORE_SIZE,
  1801.                 (unsigned long)h->Size, h->File, h->Line, h->FreedFile, h->FreedLine, h->Label);
  1802.     }
  1803.  
  1804.     return st_BlockString;
  1805. }
  1806. #endif /* FORTIFY_VERBOSE_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY */
  1807. #endif /* FORTIFY_WARN_WHEN_DISCARDING_DEALLOCATED_MEMORY */
  1808. #endif /* FORTIFY_TRACK_DEALLOCATED_MEMORY */
  1809.  
  1810.  
  1811. /*
  1812.  * st_DefaultOutput - the default output function
  1813.  */
  1814. static void
  1815. st_DefaultOutput(const char *String)
  1816. {
  1817.     fprintf(stdout, String);
  1818.     fflush(stdout);
  1819. }
  1820.  
  1821. /*
  1822.  * Fortify_malloc - Fortify's replacement malloc()
  1823.  */
  1824. void *FORTIFY_STORAGE
  1825. Fortify_malloc(size_t size, const char *file, unsigned long line)
  1826. {
  1827.     return Fortify_Allocate(size, Fortify_Allocator_malloc, file, line);
  1828. }
  1829.  
  1830. /*
  1831.  * Fortify_realloc - Fortify's replacement realloc()
  1832.  */
  1833. void *
  1834. Fortify_realloc(void *uptr, size_t new_size, const char *file, unsigned long line)
  1835. {
  1836.     unsigned char *ptr = (unsigned char *)uptr - FORTIFY_HEADER_SIZE - FORTIFY_ALIGNED_BEFORE_SIZE;
  1837.     struct Header *h = (struct Header *)ptr;
  1838.     void *new_ptr;
  1839.  
  1840.     /*
  1841.      * If Fortify is disabled, we gotta do this a little 
  1842.      * differently.
  1843.      */
  1844.     if(!st_Disabled) 
  1845.     {
  1846.         if(!uptr)
  1847.             return(Fortify_Allocate(new_size, Fortify_Allocator_realloc, file, line));
  1848.         
  1849.         if(!st_IsOnAllocatedList(h))
  1850.         {
  1851. #ifdef FORTIFY_TRACK_DEALLOCATED_MEMORY
  1852.             if(st_IsOnDeallocatedList(h))
  1853.             {
  1854.                 sprintf(st_Buffer, "\nFortify: Deallocated memory block passed to \"%s\" at %s.%lu\n",
  1855.                                     st_AllocatorName[Fortify_Allocator_realloc], file, line);
  1856.                 st_Output(st_Buffer);
  1857.                 sprintf(st_Buffer,   "         Memory block %s was deallocated by \"%s\" at %s.%lu\n",
  1858.                                    st_MemoryBlockString(h),
  1859.                                    st_DeallocatorName[h->Deallocator], h->FreedFile, h->FreedLine);
  1860.                 st_Output(st_Buffer);
  1861.                 return 0;
  1862.             }
  1863. #endif
  1864.  
  1865.             sprintf(st_Buffer, 
  1866. #ifdef FORTIFY_NO_PERCENT_P
  1867.                     "\nFortify: Invalid pointer (0x%08lx) passed to realloc at %s.%lu\n",
  1868. #else
  1869.                     "\nFortify: Invalid pointer (%p) passed to realloc at %s.%lu\n",
  1870. #endif            
  1871.                     ptr, file, line);
  1872.             st_Output(st_Buffer);
  1873.             return 0;
  1874.         }
  1875.  
  1876.         if(!st_CheckBlock(h, file, line))
  1877.             return 0;
  1878.       
  1879.         new_ptr = Fortify_Allocate(new_size, Fortify_Allocator_realloc, file, line);
  1880.         if(!new_ptr)
  1881.         {
  1882.             return(0);
  1883.         }
  1884.       
  1885.         if(h->Size < new_size) 
  1886.             memcpy(new_ptr, uptr, h->Size);
  1887.         else
  1888.             memcpy(new_ptr, uptr, new_size);
  1889.     
  1890.         Fortify_Deallocate(uptr, Fortify_Deallocator_realloc, file, line);
  1891.         return(new_ptr);
  1892.     }
  1893.     else
  1894.     {
  1895.         /*
  1896.          * If the old block was fortified, we can't use normal realloc.
  1897.          */
  1898.         if(st_IsOnAllocatedList(h))
  1899.         {
  1900.             new_ptr = Fortify_Allocate(new_size, Fortify_Allocator_realloc, file, line);
  1901.             if(!new_ptr)
  1902.                 return(0);
  1903.           
  1904.             if(h->Size < new_size) 
  1905.                 memcpy(new_ptr, uptr, h->Size);
  1906.             else
  1907.                 memcpy(new_ptr, uptr, new_size);
  1908.         
  1909.             Fortify_Deallocate(uptr, Fortify_Deallocator_realloc, file, line);
  1910.             return(new_ptr);
  1911.         }
  1912.         else /* easy */
  1913.         {
  1914.             return realloc(uptr, new_size);
  1915.         }
  1916.     }
  1917. }
  1918.  
  1919. /*
  1920.  * Fortify_calloc - Fortify's replacement calloc
  1921.  */
  1922. void *
  1923. Fortify_calloc(size_t num, size_t size, const char *file, unsigned long line)
  1924. {
  1925.     if(!st_Disabled)
  1926.     {
  1927.         void *ptr = Fortify_Allocate(size * num, Fortify_Allocator_calloc, file, line);
  1928.         if(ptr)
  1929.         {
  1930.             memset(ptr, 0, size*num);
  1931.         }
  1932.         return ptr;
  1933.     }    
  1934.     else
  1935.     {
  1936.         return calloc(num, size);
  1937.     }
  1938. }
  1939.  
  1940. /*
  1941.  * Fortify_free - Fortify's replacement free
  1942.  */
  1943. void  
  1944. Fortify_free(void *uptr, const char *file, unsigned long line)
  1945. {
  1946.     /* it is defined to be safe to free(0) */
  1947.     if(uptr == 0)
  1948.         return;
  1949.  
  1950.     Fortify_Deallocate(uptr, Fortify_Deallocator_free, file, line);
  1951. }
  1952.  
  1953. /*
  1954.  * Fortify_strdup - Fortify's replacement strdup. Since strdup isn't
  1955.  * ANSI, it is only provided if FORTIFY_STRDUP is defined.
  1956.  */
  1957. #ifdef FORTIFY_STRDUP
  1958. char *FORTIFY_STORAGE
  1959. Fortify_strdup(const char *oldStr, const char *file, unsigned long line)
  1960. {
  1961.     if(!st_Disabled)
  1962.     {
  1963.         char *newStr = Fortify_Allocate(strlen(oldStr)+1, Fortify_Allocator_strdup, file, line);
  1964.         if(newStr)
  1965.         {
  1966.             strcpy(newStr, oldStr);
  1967.         }
  1968.     
  1969.         return newStr;
  1970.     }    
  1971.     else
  1972.     {
  1973.         return strdup(oldStr);
  1974.     }
  1975. }
  1976. #endif /* FORTIFY_STRDUP */
  1977.  
  1978. static void
  1979. st_OutputDeleteTrace()
  1980. {
  1981. #ifdef __cplusplus
  1982.     if(st_DeleteStackTop > 1)
  1983.     {
  1984.         sprintf(st_Buffer, "Delete Trace: %s.%lu\n", st_DeleteFile[st_DeleteStackTop-1],
  1985.                                                      st_DeleteLine[st_DeleteStackTop-1]);
  1986.         st_Output(st_Buffer);
  1987.         for(int c = st_DeleteStackTop-2; c >= 0; c--)
  1988.         {
  1989.             sprintf(st_Buffer, "              %s.%lu\n", st_DeleteFile[c],
  1990.                                                          st_DeleteLine[c]);
  1991.             st_Output(st_Buffer);
  1992.         }
  1993.     }
  1994. #endif
  1995. }
  1996.  
  1997. #ifdef __cplusplus
  1998.  
  1999. /*
  2000.  * st_NewHandler() - there is no easy way to get
  2001.  * the new handler function. And isn't it great
  2002.  * how the new handler doesn't take a parameter
  2003.  * giving the size of the request that failed.
  2004.  * Thanks Bjarne!
  2005.  */
  2006. Fortify_NewHandlerFunc
  2007. st_NewHandler()
  2008. {
  2009.     /* get the current handler */
  2010.     Fortify_NewHandlerFunc handler = set_new_handler(0);
  2011.  
  2012.     /* and set it back (since we cant 
  2013.      * get it without changing it)
  2014.      */
  2015.     set_new_handler(handler);
  2016.     
  2017.     return handler;
  2018. }
  2019.  
  2020. /*
  2021.  * operator new - Fortify's replacement new, 
  2022.  * without source-code information.
  2023.  */
  2024. void *FORTIFY_STORAGE
  2025. operator new(size_t size)
  2026. {
  2027.     void *p;
  2028.     
  2029.     while((p = Fortify_Allocate(size, Fortify_Allocator_new, 
  2030.                                 st_AllocatorName[Fortify_Allocator_new], 0)) == 0)
  2031.     {                            
  2032.         if(st_NewHandler())
  2033.             (*st_NewHandler())();
  2034.         else
  2035.             return 0;
  2036.     }
  2037.  
  2038.     return p;
  2039. }
  2040.  
  2041. /*
  2042.  * operator new - Fortify's replacement new,
  2043.  * with source-code information
  2044.  */
  2045. void *FORTIFY_STORAGE
  2046. operator new(size_t size, const char *file, unsigned long line)
  2047. {
  2048.     void *p;
  2049.  
  2050.     while((p = Fortify_Allocate(size, Fortify_Allocator_new, file, line)) == 0)
  2051.     {
  2052.         if(st_NewHandler())
  2053.             (*st_NewHandler())();
  2054.         else
  2055.             return 0;
  2056.     }
  2057.     
  2058.     return p;
  2059. }
  2060.  
  2061. #ifdef FORTIFY_PROVIDE_ARRAY_NEW
  2062.  
  2063. /*
  2064.  * operator new[], without source-code info
  2065.  */
  2066. void *FORTIFY_STORAGE
  2067. operator new[](size_t size) 
  2068. {
  2069.     void *p;
  2070.  
  2071.     while((p = Fortify_Allocate(size, Fortify_Allocator_array_new,
  2072.                                 st_AllocatorName[Fortify_Allocator_array_new], 0)) == 0)
  2073.     {                                
  2074.         if(st_NewHandler())
  2075.             (*st_NewHandler())();    
  2076.         else    
  2077.             return 0;
  2078.     }
  2079.     
  2080.     return p;
  2081. }
  2082.  
  2083. /*
  2084.  * operator new[], with source-code info
  2085.  */
  2086. void *FORTIFY_STORAGE
  2087. operator new[](size_t size, const char *file, unsigned long line)
  2088. {
  2089.     void *p;
  2090.  
  2091.     while((p = Fortify_Allocate(size, Fortify_Allocator_array_new, file, line)) == 0)
  2092.     {
  2093.         if(st_NewHandler())
  2094.             (*st_NewHandler())(); 
  2095.         else
  2096.             return 0;
  2097.     }
  2098.  
  2099.     return p;
  2100. }
  2101.  
  2102. #endif /* FORTIFY_PROVIDE_ARRAY_NEW */
  2103.  
  2104. /*
  2105.  * Fortify_PreDelete - C++ does not allow overloading
  2106.  * of delete, so the delete macro calls Fortify_PreDelete
  2107.  * with the source-code info, and then calls delete.
  2108.  */
  2109. void FORTIFY_STORAGE
  2110. Fortify_PreDelete(const char *file, unsigned long line)
  2111. {
  2112.     FORTIFY_LOCK();
  2113.  
  2114.     /*
  2115.      * Push the source code info for the delete onto the delete stack
  2116.      * (if we have enough room, of course)
  2117.      */
  2118.     if(st_DeleteStackTop < FORTIFY_DELETE_STACK_SIZE)
  2119.     {
  2120.         st_DeleteFile[st_DeleteStackTop] = file;
  2121.         st_DeleteLine[st_DeleteStackTop] = line;
  2122.     }
  2123.  
  2124.     st_DeleteStackTop++;
  2125. }
  2126.  
  2127. /*
  2128.  * Fortify_PostDelete() - Pop the delete source-code info
  2129.  * off the source stack.
  2130.  */
  2131. void FORTIFY_STORAGE
  2132. Fortify_PostDelete()
  2133. {
  2134.     st_DeleteStackTop--;
  2135.  
  2136.     FORTIFY_UNLOCK();
  2137. }
  2138.  
  2139. /*
  2140.  * operator delete - fortify's replacement delete
  2141.  */
  2142. void FORTIFY_STORAGE
  2143. operator delete(void *uptr)
  2144. {
  2145.     const char *file;
  2146.     unsigned long line;
  2147.  
  2148.      /*
  2149.       * It is defined to be harmless to delete 0
  2150.       */
  2151.     if(uptr == 0)
  2152.         return;
  2153.  
  2154.     /*
  2155.      * find the source-code info
  2156.      */
  2157.     if(st_DeleteStackTop)
  2158.     {
  2159.         if(st_DeleteStackTop < FORTIFY_DELETE_STACK_SIZE)
  2160.         {
  2161.             file = st_DeleteFile[st_DeleteStackTop-1];
  2162.             line = st_DeleteLine[st_DeleteStackTop-1];
  2163.         }
  2164.         else
  2165.         {
  2166.             file = st_DeleteFile[FORTIFY_DELETE_STACK_SIZE-1];
  2167.             line = st_DeleteLine[FORTIFY_DELETE_STACK_SIZE-1];
  2168.         }
  2169.     }
  2170.     else
  2171.     {
  2172.         file = st_DeallocatorName[Fortify_Deallocator_delete];
  2173.         line = 0;
  2174.     }
  2175.  
  2176.     Fortify_Deallocate(uptr, Fortify_Deallocator_delete, file, line);
  2177. }
  2178.  
  2179. #ifdef FORTIFY_PROVIDE_ARRAY_DELETE
  2180.  
  2181. /*
  2182.  * operator delete[] - fortify's replacement delete[]
  2183.  */
  2184. void FORTIFY_STORAGE
  2185. operator delete[](void *uptr)
  2186. {
  2187.     const char *file;
  2188.     unsigned long line;
  2189.  
  2190.      /*
  2191.       * It is defined to be harmless to delete 0
  2192.       */
  2193.     if(uptr == 0)
  2194.         return;
  2195.  
  2196.     /*
  2197.      * find the source-code info
  2198.      */
  2199.     if(st_DeleteStackTop)
  2200.     {
  2201.         if(st_DeleteStackTop < FORTIFY_DELETE_STACK_SIZE)
  2202.         {
  2203.             file = st_DeleteFile[st_DeleteStackTop-1];
  2204.             line = st_DeleteLine[st_DeleteStackTop-1];
  2205.         }
  2206.         else
  2207.         {
  2208.             file = st_DeleteFile[FORTIFY_DELETE_STACK_SIZE-1];
  2209.             line = st_DeleteLine[FORTIFY_DELETE_STACK_SIZE-1];
  2210.         }
  2211.     }
  2212.     else
  2213.     {
  2214.         file = st_DeallocatorName[Fortify_Deallocator_array_delete];
  2215.         line = 0;
  2216.     }
  2217.  
  2218.     Fortify_Deallocate(uptr, Fortify_Deallocator_array_delete, file, line);
  2219. }
  2220.  
  2221. #endif /* FORTIFY_PROVIDE_ARRAY_DELETE */
  2222.  
  2223. #ifdef FORTIFY_AUTOMATIC_LOG_FILE
  2224. /* Automatic log file stuff!
  2225.  *
  2226.  * AutoLogFile class. There can only ever be ONE of these
  2227.  * instantiated! It is a static class, which means that
  2228.  * it's constructor will be called at program initialization,
  2229.  * and it's destructor will be called at program termination.
  2230.  * We don't know if the other static class objects have been
  2231.  * constructed/destructed yet, but this pretty much the best
  2232.  * we can do with standard C++ language features.
  2233.  */
  2234. class Fortify_AutoLogFile
  2235. {
  2236.     static FILE *fp;
  2237.     static int   written_something;
  2238.     static char *init_string, *term_string;
  2239.  
  2240. public:
  2241.     Fortify_AutoLogFile()
  2242.     {
  2243.         written_something = 0;
  2244.         Fortify_SetOutputFunc(Fortify_AutoLogFile::Output);
  2245.         Fortify_EnterScope(init_string, 0);
  2246.     }
  2247.  
  2248.     static void Output(const char *s)
  2249.     {
  2250.         if(written_something == 0)
  2251.         {
  2252.             FORTIFY_FIRST_ERROR_FUNCTION;
  2253.             fp = fopen(FORTIFY_LOG_FILENAME, "w");
  2254.             if(fp)
  2255.             {
  2256.                 time_t t;
  2257.                 time(&t);
  2258.                 fprintf(fp, "Fortify log started at %s\n", ctime(&t));
  2259.                 written_something = 1;
  2260.             }    
  2261.         }
  2262.  
  2263.         if(fp)
  2264.         {
  2265.             fputs(s, fp);
  2266.             fflush(fp);
  2267.         }    
  2268.     }
  2269.     
  2270.     ~Fortify_AutoLogFile()
  2271.     {
  2272.         Fortify_LeaveScope(term_string, 0);
  2273.         Fortify_CheckAllMemory(term_string, 0);
  2274.         if(fp)
  2275.         {
  2276.             time_t t;
  2277.             time(&t);
  2278.             fprintf(fp, "\nFortify log closed at %s\n", ctime(&t));
  2279.             fclose(fp);
  2280.             fp = 0;
  2281.         }    
  2282.     }
  2283. };
  2284.  
  2285. FILE *Fortify_AutoLogFile::fp = 0;
  2286. int   Fortify_AutoLogFile::written_something = 0;
  2287. char *Fortify_AutoLogFile::init_string = "Program Initialization";
  2288. char *Fortify_AutoLogFile::term_string = "Program Termination";
  2289.  
  2290. static Fortify_AutoLogFile Abracadabra;
  2291.  
  2292. #endif /* FORTIFY_AUTOMATIC_LOG_FILE */
  2293.  
  2294. #endif /* __cplusplus */
  2295.  
  2296. #endif /* FORTIFY */
  2297.